﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data;
using Hardcodet.Wpf.GenericTreeView;
using Cinchoo.Core;
using Cinchoo.Core.Net.Sockets;
using ChoWorkflowServer.Model;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Threading;
using Cinchoo.Core.Services;
using Cinchoo.Core.Net;
using System.Net;
using System.ComponentModel;
using System.Reflection;
using Cinchoo.Core.Win32;
using Microsoft.Win32;
using Cinchoo.Core.Diagnostics;
using Cinchoo.Core.WPF;
using System.Collections;
using Cinchoo.Core.Windows.Forms;
using MahApps.Metro.Controls;
using System.Diagnostics;
using MahApps.Metro;

namespace ChoWorkflowDashboard
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class ChoMainWindow : MetroWindow, INotifyPropertyChanged
    {
        #region Instance Data Members (Private)

        private string _title;
        internal static Window ChildWindow;
        internal static CommonDialog ChildDialog;
        private static bool _maxNoOfAllowedTasksReached;

        private Lazy<IChoDataModel> _dataModel = new Lazy<IChoDataModel>((() =>
        {
            ChoWFServerCmdLineArgsObject cmd = new ChoWFServerCmdLineArgsObject();
            cmd.RunAsPeer = true;
            return ChoDataModelFactory.New();
            }), false);
        private IChoDataModel DataModel
        {
            get { return _dataModel.Value; }
        }
        private ChoTasksDataSet.CHO_POLICYDataTable _policyForUserDataTable;
        private ChoTcpClient _tcpClient;
        public ChoTasksDataSet.CHO_TASKSDataTable TasksData { get; set; }
        public DataRowView SelectedRow { get; set; }
        private ChoWorkflowServerSettings _workflowServerSettings;
        private bool _isReady = true;
        private ChoTaskGroupCategory _copyItem;
        public ChoTaskModel Tasks { get; set; }
        internal static ChoMainWindow Instance { get; set; }
        private ChoTaskGroupCategory _lastSelectedTreeItem;
        private int _lastSelectedGridRow = -1;
        private readonly object _padLock = new object();
        private bool _init = false;
        private ChoTasksDataSet.CHO_TASKSDataTable _tasksTable = new ChoTasksDataSet.CHO_TASKSDataTable();
        private string[] _machines = new string[] { };
        private string[] _wfNames = new string[] { };
        public event PropertyChangedEventHandler PropertyChanged;
        private ChoClusterNodesViewer _clusterNodesViewerWnd = null;
        private readonly Timer _refreshTimer = null;
        private bool _doRefreshContents = false;

        #endregion Instance Data Members (Private)

        private bool _isManageUsersEnabled;
        public bool IsManageUsersEnabled
        {
            get { return _isManageUsersEnabled; }
            set
            {
                _isManageUsersEnabled = value;
                RaisePropertyChangedEvent("IsManageUsersEnabled");
            }
        }

        private bool _isEditHolidayCalendarEnabled;
        public bool IsEditHolidayCalendarEnabled
        {
            get { return _isEditHolidayCalendarEnabled; }
            set
            {
                _isEditHolidayCalendarEnabled = value;
                RaisePropertyChangedEvent("IsEditHolidayCalendarEnabled");
            }
        }

        private bool _isUserPolicyEnabled;
        public bool IsUserPolicyEnabled
        {
            get { return _isUserPolicyEnabled; }
            set
            {
                _isUserPolicyEnabled = value;
                RaisePropertyChangedEvent("IsUserPolicyEnabled");
            }
        }

        public bool IsAddTaskEnabled
        {
            get;
            set;
        }

        public bool IsRemoveTaskEnabled
        {
            get;
            set;
        }

        public bool IsCopyTaskEnabled
        {
            get;
            set;
        }

        public bool IsPasteTaskEnabled
        {
            get;
            set;
        }

        public bool IsMoveTaskEnabled
        {
            get;
            set;
        }

        public bool IsExportTaskEnabled
        {
            get;
            set;
        }

        public bool IsImportTaskEnabled
        {
            get;
            set;
        }

        public bool IsEditTaskEnabled
        {
            get;
            set;
        }

        public bool IsStartTaskEnabled
        {
            get;
            set;
        }

        public bool IsResumeTaskEnabled
        {
            get;
            set;
        }

        public bool IsInactivateTaskEnabled
        {
            get;
            set;
        }

        public bool IsStopTaskEnabled
        {
            get;
            set;
        }

        public bool IsAbortTaskEnabled
        {
            get;
            set;
        }

        public bool IsActivateTaskEnabled
        {
            get;
            set;
        }

        #region Constructors

        public ChoMainWindow()
        {
            _refreshTimer = new Timer(RefreshContents, null, 5000, 5000);
            TasksData = new ChoTasksDataSet.CHO_TASKSDataTable();

            //Add Primary Key to TasksData table
            TasksData.PrimaryKey = new DataColumn[] { TasksData.TASK_IDColumn, TasksData.SCHEDULE_NAMEColumn };

            InitializeComponent();
            Instance = this;
            Tasks = new ChoTaskModel();

            //ChoUser.CurrentUser = "xbbjhw0";
            if (!ChoApplication.AppEnvironment.IsNullOrWhiteSpace())
                tblTitle.Text = "{0} [{1}]".FormatString(tblTitle.Text, ChoApplication.AppEnvironment);
        }

        #endregion Constructors

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _title = this.Title;
            Task.Factory.StartNew(() =>
            {
                using (ChoWaitCursor wait = new ChoWaitCursor())
                {
                    try
                    {
                        Version taskModelVersion = DataModel.GetVersion();
                        if (Assembly.GetAssembly(typeof(IChoDataModel)).GetName().Version != taskModelVersion)
                            throw new ApplicationException("The new version of the application available at this time. Please contact administrator.");

                        //_machines.Add("D076WCS004021NN");
                        //IsManageUsersEnabled = true;
                        //LoadRolePolicy();
                    }
                    catch
                    {
                    }
                    _workflowServerSettings = new ChoWorkflowServerSettings();
                    Reconnect();
                    //Refresh(true);
                }
            });
        }

        private void LoadRolePolicy()
        {
            IsManageUsersEnabled = DataModel.IsUserPolicyEnabled();
            if (IsManageUsersEnabled)
            {
                ResetPolicy();
                _policyForUserDataTable = GetPolicyForUser();

                if (_policyForUserDataTable == null ||
                    _policyForUserDataTable.Count == 0)
                {
                    ChoInputWindow wnd = new ChoInputWindow(ChoUser.CurrentUser, "Enter User Id", CharacterCasing.Upper);
                    bool? ret = ShowDialog(wnd);
                    if (ret == null || !ret.Value)
                        return;
                    //Environment.Exit(0);

                    ChoUser.CurrentUser = wnd.InputText;
                    _policyForUserDataTable = GetPolicyForUser();

                    if (_policyForUserDataTable == null ||
                        _policyForUserDataTable.Count == 0)
                    {
                        Application.Current.Dispatcher.Invoke(new Action(() => MessageBox.Show("You [ID: {1}] are not allowed to connect to the {0} environment. Please contact administrator.".FormatString(ChoApplication.AppEnvironment.IsNullOrWhiteSpace() ? null : ChoApplication.AppEnvironment, ChoUser.CurrentUser), Title, MessageBoxButton.OK, MessageBoxImage.Stop)));
                        return;
                    }
                    //throw new ChoFatalApplicationException("You [ID: {1}] are not allowed to connect '{0}' environment. Please contact administrator.".FormatString(ChoApplication.AppEnvironment, ChoUser.CurrentUser));
                }

                Application.Current.Dispatcher.Invoke(new Action(() => this.Title = "{0} v{1} [User: {2}]".FormatString(_title, Assembly.GetExecutingAssembly().GetName().Version, ChoUser.CurrentUser)));
                ChoTrace.WriteLine("Login as {0}...[TableCount: {1}]".FormatString(ChoUser.CurrentUser, _policyForUserDataTable.Count));

                var x = (from z in _policyForUserDataTable.AsEnumerable()
                         where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.ManageUsers
                         select z).FirstOrDefault();

//#if DEBUG
//                IsManageUsersEnabled = true;
//#else
//            IsManageUsersEnabled = x != null;
//#endif
                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.EditHolidayCalendar
                     select z).FirstOrDefault();

                IsEditHolidayCalendarEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.AddTask
                     select z).FirstOrDefault();

                IsAddTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.RemoveTask
                     select z).FirstOrDefault();

                IsRemoveTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.CopyTask
                     select z).FirstOrDefault();

                IsCopyTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.PasteTask
                     select z).FirstOrDefault();

                IsPasteTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.MoveTask
                     select z).FirstOrDefault();

                IsMoveTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.ExportTask
                     select z).FirstOrDefault();

                IsExportTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.ImportTask
                     select z).FirstOrDefault();

                IsImportTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.EditTask
                     select z).FirstOrDefault();

                IsEditTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.StartTask
                     select z).FirstOrDefault();

                IsStartTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.ResumeTask
                     select z).FirstOrDefault();

                IsResumeTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.StopTask
                     select z).FirstOrDefault();

                IsStopTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.AbortTask
                     select z).FirstOrDefault();

                IsAbortTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.ActivateTask
                     select z).FirstOrDefault();

                IsActivateTaskEnabled = x != null;

                x = (from z in _policyForUserDataTable.AsEnumerable()
                     where ((ChoPolicy)z.POLICY_ID) == ChoPolicy.DeactivateTask
                     select z).FirstOrDefault();

                IsInactivateTaskEnabled = x != null;
            }
            else
            {
                //IsManageUsersEnabled = true;
                IsEditHolidayCalendarEnabled = true;
                IsAddTaskEnabled = true;
                IsRemoveTaskEnabled = true;
                IsCopyTaskEnabled = true;
                IsPasteTaskEnabled = true;
                IsMoveTaskEnabled = true;
                IsExportTaskEnabled = true;
                IsImportTaskEnabled = true;
                IsEditTaskEnabled = true;
                IsStartTaskEnabled = true;
                IsResumeTaskEnabled = true;
                IsStopTaskEnabled = true;
                IsAbortTaskEnabled = true;
                IsActivateTaskEnabled = true;
                IsInactivateTaskEnabled = true;
            }
        }

        private void ResetPolicy()
        {
            //IsManageUsersEnabled = false;
            IsEditHolidayCalendarEnabled = false;
            IsAddTaskEnabled = false;
            IsRemoveTaskEnabled = false;
            IsCopyTaskEnabled = false;
            IsPasteTaskEnabled = false;
            IsMoveTaskEnabled = false;
            IsExportTaskEnabled = false;
            IsImportTaskEnabled = false;
            IsEditTaskEnabled = false;
            IsStartTaskEnabled = false;
            IsResumeTaskEnabled = false;
            IsStopTaskEnabled = false;
            IsAbortTaskEnabled = false;
            IsActivateTaskEnabled = false;
            IsInactivateTaskEnabled = false;
        }

        private ChoTasksDataSet.CHO_POLICYDataTable GetPolicyForUser()
        {
            try
            {
                return DataModel.GetPolicyForUser(ChoUser.CurrentUser);
            }
            catch
            {
                return null;
            }
        }

        internal void OnMsgObjectReceived(object msg)
        {
            if (msg == null) return;

            ChoCommandMessage cmdMsg = msg as ChoCommandMessage;
            if (cmdMsg != null)
            {
                if ((cmdMsg.IsUniversalMessage /*&& !msg.IsLoopbackMessage */) || cmdMsg.HostName == Environment.MachineName)
                {
                    if (_isReady)
                    {
                        if (cmdMsg.Command is ChoTaskMsgPayload)
                            Application.Current.Dispatcher.Invoke(new Action(() => ((ChoTaskMsgPayload)cmdMsg.Command).ApplyChanges(TasksData)));
                        else if (cmdMsg.Command is ChoTaskMgmtCommand)
                            ProcessTaskMgmtCommand(cmdMsg.Command as ChoTaskMgmtCommand);
                        else if (cmdMsg.Command is ChoMachinesCommand)
                        {
                            ChoMachinesCommand machinesCommand = cmdMsg.Command as ChoMachinesCommand;
                            if (machinesCommand.Machines != null)
                            {
                                Application.Current.Dispatcher.Invoke(new Action(() => _machines = machinesCommand.Machines.ToDictionary(x => x.Key, y => y.Value).Keys.ToArray()));
                            }
                        }
                        else if (cmdMsg.Command is ChoWFListCommand)
                        {
                            ChoWFListCommand wfListCommand = cmdMsg.Command as ChoWFListCommand;
                            if (wfListCommand.WFNames != null)
                            {
                                Application.Current.Dispatcher.Invoke(new Action(() => _wfNames = wfListCommand.WFNames.ToArray()));
                            }
                        }
                        else if (cmdMsg.Command is ChoClientCtrlCommand)
                        {
                            ChoClientCtrlCommand clientCtrlCommand = cmdMsg.Command as ChoClientCtrlCommand;
                            _maxNoOfAllowedTasksReached = clientCtrlCommand.MaxNoOfAllowedTasksReached;
                        }
                        else if (cmdMsg.Command is ChoUsersACLChangedCommand)
                        {
                            if (Application.Current != null && Application.Current.Dispatcher != null)
                            {
                                Application.Current.Dispatcher.Invoke(new Action(LoadRolePolicy));
                            }
                        }
                        else if (cmdMsg.Command is ChoCalendarCommand)
                        {
                            if (ChoMainWindow.ChildWindow is ChoBaseWindow)
                            {
                                ((ChoBaseWindow)ChildWindow).RaiseRefreshData();
                            }
                        }
                        else if (cmdMsg.Command is ChoWFPlugInsChangedCommand)
                            ChoWFPlugInsFolderSynchronizer.Value.SyncNow();
                        else if (cmdMsg.Command is ChoServerMsgCommand)
                            DisplayMsgBox(cmdMsg.Command as ChoServerMsgCommand);
                    }
                }
            }
            else
            {
            }
        }

        private void DisplayMsgBox(ChoServerMsgCommand cmd)
        {
            if (cmd == null) return;

            string errMsg;
            if (cmd.ErrorCode == 0)
                errMsg = cmd.Message;
            else
                errMsg = "[ERROR: {0}] - {1}".FormatString(cmd.ErrorCode, cmd.Message);

            switch (cmd.Severity)
            {
                case Severity.Critical:
                    Application.Current.Dispatcher.Invoke(new Action(() => MessageBox.Show(errMsg, Title, MessageBoxButton.OK, MessageBoxImage.Stop)));
                    break;
                case Severity.Error:
                    Application.Current.Dispatcher.Invoke(new Action(() => MessageBox.Show(errMsg, Title, MessageBoxButton.OK, MessageBoxImage.Error)));
                    break;
                default:
                    Application.Current.Dispatcher.Invoke(new Action(() => MessageBox.Show(errMsg, Title, MessageBoxButton.OK, MessageBoxImage.Information)));
                    break;
            }
        }

        private void Reconnect()
        {
            if (Application.Current != null && Application.Current.Dispatcher != null)
            {
                UpdateServerStatusWithMsg("Connecting to server...", false);
                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
                    {
                        ChoWSUDPConnectionManager.Instance.StartAsClient();

                        IChoDataModel dataModel = ChoDataModelFactory.New();
                        ChoGuard.ArgumentNotNull(dataModel, "DataModel");
                        ChoWFPlugInsFolderSynchronizer.Value.Start(() => dataModel.GetWFPlugInsFileList(), (fileName) => dataModel.DownloadWFPlugIn(fileName));

                        _dataModel = new Lazy<IChoDataModel>(() => ChoDataModelFactory.New(), false);
                        StartListeningToMessages();
                    }));
            }
        }

        internal void Refresh()
        {
            using (ChoWaitCursor wait = new ChoWaitCursor())
            {
                _init = true;
                //btnRefresh.IsEnabled = false;
                btnHolidayCal.IsEnabled = false;
                btnViewClusters.IsEnabled = false;
                btnAdminUsers.IsEnabled = false;
                btnAdminRoles.IsEnabled = false;
                btnAdminRoles.IsEnabled = false;

                LoadRolePolicy();
                
                try
                {
                    this.DataContext = null;

                    Tasks.Refresh();

                    BuildTaskGridData(null);

                    this.DataContext = this;
                    //if (reconnect)
                    //    StartListeningToMessages();
                }
                finally
                {
                    _init = false;
                    //btnRefresh.IsEnabled = true;
                    btnHolidayCal.IsEnabled = true;
                    btnViewClusters.IsEnabled = true;
                    btnAdminUsers.IsEnabled = true;
                    btnAdminRoles.IsEnabled = true;
                    btnAdminRoles.IsEnabled = true;
                }

                SelectLastSelectedItems();

                //dgTasks.ColumnFromDisplayIndex(0).SortDirection = ListSortDirection.Ascending;
            }
        }

        private void SelectLastSelectedItems()
        {
            if (_lastSelectedTreeItem != null)
            {
                LoadGridData(_lastSelectedTreeItem);
                TreeViewItem item = TasksTree.TryFindNode(_lastSelectedTreeItem);
                if (item == null)
                {
                    item = TasksTree.RootNode;
                    _lastSelectedGridRow = -1;
                }
                if (item != null)
                {
                    TasksTree.TryFindNode(_lastSelectedTreeItem).IsSelected = true;
                    TasksTree.TryFindNode(_lastSelectedTreeItem).IsExpanded = true;

                    if (_lastSelectedGridRow >= 0)
                        dgTasks.SelectedIndex = _lastSelectedGridRow;
                }
            }
        }

        private void StartListeningToMessages()
        {
            if (_tcpClient != null)
            {
                try
                {
                    _tcpClient.Stop();
                }
                catch { }
            }


            try {
                if (!_workflowServerSettings.ControllerIPAddress.IsNullOrWhiteSpace())
                {
                    _tcpClient = new ChoTcpClient(new IPEndPoint(IPAddress.Parse(_workflowServerSettings.ControllerIPAddress), _workflowServerSettings.Port));
                    _tcpClient.Connected += (sender, evtArg) =>
                    {
                        ChoTrace.WriteLine("Connected to controller....");

                        if (Application.Current != null && Application.Current.Dispatcher != null)
                        {
                            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action<Exception>(UpdateServerStatus), null);
                            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(Refresh));
                        }
                        ChoSubscribeCommand subscribeServerCommand = new ChoSubscribeCommand();
                        subscribeServerCommand.HostName = Environment.MachineName;
                        subscribeServerCommand.SubscriberType = ChoSubscriberType.Client;

                        ChoCommandMessage commandMsg = new ChoCommandMessage();
                        commandMsg.Command = subscribeServerCommand;

                        ((ChoTcpClient)sender).Send(commandMsg);
                    };
                    _tcpClient.Disconnected += (sender, evtArg) =>
                    {
                        ChoTrace.WriteLine("Disconnected from controller....");
                        if (Application.Current != null && Application.Current.Dispatcher != null)
                            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action<Exception>(UpdateServerStatus), new SocketException());

                    //if (_workflowServerSettings.TurnOnUDP)
                    //{
                    //    try
                    //    {
                    //        ((ChoTcpClient)sender).Stop();
                    //    }
                    //    catch { }
                    //    Task.Factory.StartNew(() =>
                    //    {
                    //        Reconnect();
                    //    }).LogExceptions();
                    //}
                };

                    _tcpClient.OnObjectRecieved = ((st, e) =>
                        {
                            OnMsgObjectReceived(e);
                        });

                    _tcpClient.Start();
                }
            }
            catch (Exception ex)
            {
                UpdateServerStatusWithMsg("Server unavailable.", false);
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        #region SelectedItemChanged event

        private void UpdateServerStatusWithMsg(string msg, bool enable)
        {
            if (Application.Current != null && Application.Current.Dispatcher != null && Dispatcher.CurrentDispatcher != Application.Current.Dispatcher)
            {
                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action<string, bool>(UpdateServerStatusWithMsg), msg, enable);
                return;
            }

            if (enable)
            {
                //if (!spOtherCmds.IsEnabled)
                    grdContent.IsEnabled = spOtherCmds.IsEnabled = true;

                txtStatus.Text = msg;
            }
            else
            {
                txtStatus.Text = msg;

                //if (spOtherCmds.IsEnabled)
                //{
                    grdContent.IsEnabled = spOtherCmds.IsEnabled = false;

                    if (_clusterNodesViewerWnd != null)
                    {
                        _clusterNodesViewerWnd.Close();
                        _clusterNodesViewerWnd = null;
                    }
                    if (ChildWindow != null)
                    {
                        try
                        {
                            if (ChildWindow != null)
                            {
                                if (ChildWindow is ChoBaseWindow)
                                {
                                    ((ChoBaseWindow)ChildWindow).Silent = true;
                                }
                                ChildWindow.Close();
                            }
                        }
                        catch
                        {
                        }
                        finally
                        {
                            ChildWindow = null;
                        }
                    }
                //}
            }
        }

        private void UpdateServerStatus(Exception ex)
        {
            if (ex == null)
                UpdateServerStatusWithMsg("Connected to '{0}:{1}' Server.".FormatString(_workflowServerSettings.ControllerIPAddress, _workflowServerSettings.Port), true);
            else
                UpdateServerStatusWithMsg("'{0}:{1}' Server Unavailable.".FormatString(_workflowServerSettings.ControllerIPAddress, _workflowServerSettings.Port), false);
        }

        private void TasksTree_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            this.EditCategory(null, null);
        }

        /// <summary>
        /// Handles the tree's <see cref="TreeViewBase{T}.SelectedItemChanged"/>
        /// event and updates the status bar.
        /// </summary>
        private void OnSelectedItemChanged(object sender, RoutedTreeItemEventArgs<ChoTaskGroupCategory> e)
        {
            SetTaskGroupComments(e.NewItem);

            if (!_init)
            {
                _lastSelectedTreeItem = e.NewItem;
                _lastSelectedGridRow = -1;
            }
            LoadGridData(e.NewItem);
        }

        private void SetTaskGroupComments(ChoTaskGroupCategory e)
        {
            if (e != null)
            {
                txtTaskComments.Text = String.Format("{0}", e.Description.IsNullOrWhiteSpace() ? "" : e.Description);
                txtTaskComments.ToolTip = e.AuditInfo.IsNullOrWhiteSpace() ? null : e.AuditInfo;
            }
            else
            {
                txtStatus.Text = "";
                txtTaskComments.ToolTip = null;
            }
        }

        private void LoadGridData(ChoTaskGroupCategory taskGroupCategory)
        {
            //_isReady = false;
            BuildTaskGridData(taskGroupCategory);
            //_isReady = true;
        }

        private void BuildTaskGridData(ChoTaskGroupCategory taskGroupCategory)
        {
            int lastSelectedGridRow = _lastSelectedGridRow;

            TasksData.Clear();

            try
            {
                foreach (ChoTasksDataSet.CHO_TASKSRow row in ChoTaskModel.GetData(taskGroupCategory, false))
                {
                    if (row.IsTASK_NAMENull() || row.IsTASK_IDNull()) continue;
                    //if (row.IsSCHEDULE_NAMENull()) continue;
                    TasksData.ImportRow(row);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message,Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            foreach (System.Data.DataColumn col in TasksData.Columns)
            {
                if (String.IsNullOrWhiteSpace(col.Expression))
                    col.ReadOnly = false;
            }

            //Add expression columns
            if (TasksData.Columns["JOB_NAME"] == null)
                TasksData.Columns.Add("JOB_NAME", typeof(String), @"TASK_NAME + '/' + SCHEDULE_NAME");
            TasksData.DefaultView.Sort = "JOB_NAME ASC";

            _lastSelectedGridRow = lastSelectedGridRow;
        }

        #endregion

        private void RefreshContents(object state)
        {
            if (!_doRefreshContents) return;

            _refreshTimer.Change(Timeout.Infinite, Timeout.Infinite);
            try
            {
                if (Application.Current != null && Application.Current.Dispatcher != null)
                    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(Refresh));

                _doRefreshContents = false;
            }
            finally
            {
                _refreshTimer.Change(5000, 5000);
            }
        }

        private void ProcessTaskMgmtCommand(ChoTaskMgmtCommand taskMgmtCommand)
        {
            _doRefreshContents = true;

            //if (!taskMgmtCommand.TaskName.IsNullOrWhiteSpace())
            //    UpdateTask(taskMgmtCommand);
            //else if (!taskMgmtCommand.TaskGroupName.IsNullOrWhiteSpace())
            //    UpdateTaskGroup(taskMgmtCommand);
            //else
            //    UpdateAllTaskGroup(taskMgmtCommand);
        }

        //private void UpdateAllTaskGroup(ChoTaskMgmtCommand taskMgmtCommand)
        //{
        //    lock (_padLock)
        //    {
        //        if (Application.Current != null && Application.Current.Dispatcher != null)
        //            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(Refresh));
        //    }
        //}

        //private void UpdateTaskGroup(ChoTaskMgmtCommand taskMgmtCommand)
        //{
        //    lock (_padLock)
        //    {
        //        if (Application.Current != null && Application.Current.Dispatcher != null)
        //            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(Refresh));
        //    }

        //    #region Commented

        //    //if (taskMgmtCommand.TaskMgmtType == ChoTaskMgmtType.Add
        //    //    || taskMgmtCommand.TaskMgmtType == ChoTaskMgmtType.Update)
        //    //{
        //    //    //Update the Tree

        //    //}
        //    //else if (taskMgmtCommand.TaskMgmtType == ChoTaskMgmtType.Remove)
        //    //{
        //    //    //Delete the group from Tree
        //    //    ChoQueuedExecutionService.Global.Enqueue(() =>
        //    //        {

        //    //        });
        //    //}

        //    #endregion Commented
        //}

        //private void UpdateTask(ChoTaskMgmtCommand taskMgmtCommand)
        //{
        //    lock (_padLock)
        //    {
        //        if (Application.Current != null && Application.Current.Dispatcher != null)
        //            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(Refresh));
        //    }

        //    #region Commented

        //    //if (taskMgmtCommand.TaskMgmtType == ChoTaskMgmtType.Add
        //    //    || taskMgmtCommand.TaskMgmtType == ChoTaskMgmtType.Update)
        //    //{
        //    //    lock (_padLock)
        //    //    {
        //    //        TaskGroupCategory cat = Tasks.FlatCategories.FirstOrDefault((category) => category.Name == taskMgmtCommand.TaskName);
        //    //        if (cat == null)
        //    //        {
        //    //            TaskModel.Load(Tasks, taskMgmtCommand.TaskName);

        //    //            if (Application.Current != null && Application.Current.Dispatcher != null)
        //    //                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(Refresh));
        //    //        }
        //    //        else
        //    //        {
        //    //            TaskModel.Refresh(cat);
        //    //            //SelectCategory(cat);
        //    //        }
        //    //    }
        //    //}
        //    //else if (taskMgmtCommand.TaskMgmtType == ChoTaskMgmtType.Remove)
        //    //{
        //    //    lock (_padLock)
        //    //    {
        //    //        TaskGroupCategory cat = Tasks.FlatCategories.FirstOrDefault((category) => category.Name == taskMgmtCommand.TaskName);
        //    //        if (cat == null) return;

        //    //        Tasks.Remove(cat);
        //    //    }
        //    //}

        //    #endregion Commented
        //}

        private void SelectCategory(ChoTaskGroupCategory cat)
        {
            ChoTaskModel.Refresh(cat);
            SelectLastSelectedItems();
        }

        private void dgTasks_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            ChoWDGridStyleObject gridStyleObject = new ChoWDGridStyleObject();
            try
            {
                if (gridStyleObject.GetColumnDisplayIndex(e.Column.Header.ToString()) >= 0)
                    e.Column.DisplayIndex = gridStyleObject.GetColumnDisplayIndex(e.Column.Header.ToString());
            }
            catch { }
            e.Column.Width = gridStyleObject.GetColumnWidth(e.Column.Header.ToString());
            e.Cancel = !gridStyleObject.GetColumnVisibility(e.Column.Header.ToString());
            e.Column.Header = gridStyleObject.GetColumnHeader(e.Column.Header.ToString());
        }

        /// <summary>
        /// Checks whether it is allowed to delete a category, which is only
        /// allowed for nested categories, but not the root items.
        /// </summary>
        private void EvaluateCanDelete(object sender, CanExecuteRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null || item.Parent == null) return;

            e.CanExecute = item.Parent != null;
            e.Handled = true;
        }

        private void DeleteCategory(object sender, ExecutedRoutedEventArgs e)
        {
            //get item
            ChoTaskGroupCategory item = GetCommandItem(true);
            if (item == null || item.Parent == null) return;

            //bool canSendMsg = false;
            try
            {
                //remove from parent
                if (item.Parent != null)
                {
                    int id = item._id;
                    if (item.IsTaskGroup) //Remove Group
                    {
                        if (MessageBox.Show("Are you sure you want to delete '{0}' task group?".FormatString(item.Name), Title, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No)
                            == MessageBoxResult.No)
                            return;

                        DataModel.DeleteTaskGroup(item.Name, ChoUser.CurrentUser, Environment.MachineName);

                        SendTaskMgmtCommand(0, null, null, item._id, item.Name, null, ChoTaskChangeType.Remove);
                    }
                    else
                    {
                        if (MessageBox.Show("Are you sure you want to delete '{0}' task?".FormatString(item.Name), Title, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No)
                            == MessageBoxResult.No)
                            return;
                        DataModel.DeleteTask(item.Name, ChoUser.CurrentUser, Environment.MachineName);
                        //canSendMsg = true;
                        SendTaskMgmtCommand(item._id, item.Name, item.WorkflowName, item.Parent._id, item.Parent.Name, item.ScheduleName, ChoTaskChangeType.Remove);
                    }

                    item.Parent.Tasks.Remove(item);
                }

                TasksTree.TryFindNode(item.Parent).IsExpanded = true;
                TasksTree.TryFindNode(item.Parent).IsSelected = true;

                //if (canSendMsg)
                //    SendTaskMgmtCommand(item._id, item.Name, item.WorkflowName, item.Parent._id, item.Parent.Name, item.ScheduleName, ChoOperationType.Remove);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }

            //mark event as handled
            e.Handled = true;
        }

        private void EvaluateCanEdit(object sender, CanExecuteRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null || item.Parent == null) return;

            e.CanExecute = item.Parent != null;
            e.Handled = true;
        }

        private void EditCategory(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem(true);
            
            if (item == null || item.Parent == null) return;
            //bool canSendMsg = false;

            try
            {

                if (item.IsTaskGroup)
                {
                    AddOrEditTaskGroupWindow wnd = new AddOrEditTaskGroupWindow(item, true);
                    bool? retValue = ShowDialog(wnd);
                    if (retValue == null || !retValue.Value)
                        return;

                    SetTaskGroupComments(item);
                    //canSendMsg = true;
                }
                else
                {
                    AddOrEditTaskWindow wnd = new AddOrEditTaskWindow(item, _machines, _wfNames, true);
                    bool? retValue = ShowDialog(wnd);
                    if (retValue == null || !retValue.Value)
                        return;

                    SendTaskMgmtCommand(item._id, item.Name, item.WorkflowName, item.Parent._id, item.Parent.Name, item.ScheduleName, ChoTaskChangeType.Update);

                    //canSendMsg = wnd.IsDataUpdated;
                }
                Refresh();
                //LoadGridData(item);

                ////make sure the parent is expanded
                //TasksTree.TryFindNode(item).IsExpanded = true;
                //TasksTree.TryFindNode(item).IsSelected = true;

                //NOTE this would be an alternative to force layout preservation
                //even if the PreserveLayoutOnRefresh property was false:
                //TreeLayout layout = CategoryTree.GetTreeLayout();
                //CategoryTree.Refresh(layout);
                //if (canSendMsg)
                //    SendTaskMgmtCommand(item._id, item.Name, item.WorkflowName, item.Parent._id, item.Parent.Name, item.ScheduleName, ChoOperationType.Update);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            //Important - mark the event as handled
            if (e != null)
                e.Handled = true;
        }

        private void EvaluateCanCopy(object sender, CanExecuteRoutedEventArgs e)
        {
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null || item.Parent == null) return;

            e.CanExecute = item.Parent != null && item.Tasks.Count == 0;
            e.Handled = true;
        }

        private void CopyCategory(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            _copyItem = GetCommandItem(true);
        }

        private void EvaluateCanPaste(object sender, CanExecuteRoutedEventArgs e)
        {
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null || item.Parent == null) return;

            e.CanExecute = (item.Parent != null && item.Parent.Parent == null) && _copyItem != null;
            e.Handled = true;
        }

        private void PasteCategory(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem(true);
            if (item == null || _copyItem == null) return;

            ChoInputWindow wnd = new ChoInputWindow(_copyItem.Name, "Enter task name", CharacterCasing.Upper);
            bool? ret = ShowDialog(wnd);
            if (ret == null || !ret.Value)
                return;

            string newTaskName = wnd.InputText; 
            
            if (newTaskName.IsNullOrWhiteSpace())
            {
                //MessageBox.Show("Please input valid task name.", "Invalid task name", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }
            if (newTaskName == item.Name)
            {
                MessageBox.Show("Please input unique task name.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            try
            {
                CheckMaxNoOfAllowdTasksReached();

                int newTaskId = DataModel.CloneTask(_copyItem.Name, newTaskName, _copyItem.GroupName, item.Name, ChoUser.CurrentUser, Environment.MachineName);
                AddTaskToTree(item, newTaskName, newTaskId);
                TasksTree.TryFindNode(item).IsSelected = true;

                //SendTaskMgmtCommand(newTaskId, newTaskName, _copyItem.WorkflowName, item._id, item.Name, item.ScheduleName, ChoOperationType.Add);
                //_copyItem = null;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        internal static void CheckMaxNoOfAllowdTasksReached()
        {
            if (_maxNoOfAllowedTasksReached)
            {
                throw new ApplicationException("Maximum number allowed tasks reached.");
            }
        }

        private void EvaluateCanMove(object sender, CanExecuteRoutedEventArgs e)
        {
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null || item.Parent == null) return;

            e.CanExecute = (item.Parent != null && item.Parent.Parent == null) && _copyItem != null;
            if (e.CanExecute)
                e.CanExecute = _copyItem.Parent.Id != item.Id;

            e.Handled = true;
        }

        private void MoveCategory(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem(true);
            if (item == null || _copyItem == null) return;

            try
            {
                DataModel.MoveTask(_copyItem.Name, _copyItem.Parent.Id, item.Id, ChoUser.CurrentUser, Environment.MachineName);
                _copyItem.Parent.Tasks.Remove(_copyItem);
                AddTaskToTree(item, _copyItem.Name, _copyItem.Id);
                TasksTree.TryFindNode(item).IsSelected = true;

                //SendTaskMgmtCommand(_copyItem.Id, _copyItem.Name, _copyItem.WorkflowName, item._id, item.Name, item.ScheduleName, ChoOperationType.Add);
                _copyItem = null;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void EvaluateCanExport(object sender, CanExecuteRoutedEventArgs e)
        {
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null /*|| item.Parent == null*/) return;

            e.CanExecute = true;
            e.Handled = true;
        }

        private void ExportCategory(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem(true);
            if (item == null /*|| item.Parent == null*/) return;

            string fileName = null;
            ChoTasksDataSet.CHO_TASKSDataTable tasksTable = null;
            ChoTasksDataSet.CHO_TASK_SCHEDULESDataTable taskSchedulesTable = null;
            try
            {
                if (item.Parent == null) //Root
                {
                    fileName = "AllTasks";
                    tasksTable = DataModel.GetAllUITasks(null, null);
                }
                else if (item.Parent.Parent == null) //Group
                {
                    fileName = item.Name;
                    tasksTable = DataModel.GetAllUITasks(null, item.Name);
                }
                else //Task
                {
                    fileName = item.Name;
                    tasksTable = DataModel.GetAllUITasks(item.Name, item.Parent.Name);
                }

                if (tasksTable == null || tasksTable.Count == 0) return;

                ChoTasksDataSet dataSet = new ChoTasksDataSet();
                foreach (ChoTasksDataSet.CHO_TASKSRow taskRow in
                    (from oRow in tasksTable select oRow).Distinct(CHO_TASKSDataTableComparer.Default))
                {
                    if (taskRow.IsTASK_IDNull()) continue;

                    dataSet.CHO_TASKS.ImportRow(taskRow);

                    //Import Task Schedules
                    taskSchedulesTable = DataModel.GetTaskSchedules(taskRow.TASK_ID, null);
                    if (taskSchedulesTable != null)
                    {
                        foreach (ChoTasksDataSet.CHO_TASK_SCHEDULESRow taskScheduleRow in taskSchedulesTable)
                        {
                            taskScheduleRow.CREATED_DATE = DateTime.Now;
                            taskScheduleRow.CREATED_BY = ChoUser.CurrentUser;
                            taskScheduleRow.MODIFIED_DATE = DateTime.Now;
                            taskScheduleRow.MODIFIED_BY = ChoUser.CurrentUser;

                            dataSet.CHO_TASK_SCHEDULES.ImportRow(taskScheduleRow);
                        }
                    }
                }

                SaveFileDialog dlg = new SaveFileDialog();
                dlg.FileName = fileName.IsNullOrWhiteSpace() ? "Document" : fileName; // Default file name
                dlg.DefaultExt = ".wfd"; // Default file extension
                dlg.Filter = "Workflow Def documents|*.wfd"; // Filter files by extension

                // Show save file dialog box
                bool? result = ShowDialog(dlg);

                // Process save file dialog box results
                if (result == true)
                {
                    // Save document
                    string filename = dlg.FileName;
                    using (System.IO.StreamWriter xmlSW = new System.IO.StreamWriter(filename))
                        dataSet.WriteXml(xmlSW);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void EvaluateCanImport(object sender, CanExecuteRoutedEventArgs e)
        {
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null) return;

            e.CanExecute = item.Parent == null;
            e.Handled = true;
        }

        private void ImportCategory(object sender, ExecutedRoutedEventArgs e)
        {
            ChoTasksDataSet.CHO_TASK_SCHEDULESDataTable taskSchedulesTable = new ChoTasksDataSet.CHO_TASK_SCHEDULESDataTable();

            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                //dlg.FileName = "Document"; // Default file name
                dlg.DefaultExt = ".wfd"; // Default file extension
                dlg.Filter = "Workflow Def documents|*.wfd"; // Filter files by extension

                // Show save file dialog box
                bool? result = ShowDialog(dlg);

                // Process save file dialog box results
                if (result == true)
                {
                    // Save document
                    string filename = dlg.FileName;
                    if (filename.IsNullOrWhiteSpace()) return;

                    ChoTasksDataSet dataSet = new ChoTasksDataSet();
                    dataSet.ReadXml(filename);

                    DataModel.ImportTasks(dataSet, ChoUser.CurrentUser, Environment.MachineName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void AddTaskToTree(ChoTaskGroupCategory item, string newTaskName, int newTaskId)
        {
            ChoTaskGroupCategory subCategory = new ChoTaskGroupCategory(newTaskId, newTaskName, null, item);
            ChoTaskModel.Refresh(subCategory);
            LoadGridData(item);
            item.Tasks.Add(subCategory);
        }

        /// <summary>
        /// Checks whether it is allowed to delete a category, which is only
        /// allowed for nested categories, but not the root items.
        /// </summary>
        private void EvaluateCanAddTaskGroup(object sender, CanExecuteRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null) return;

            e.CanExecute = item.IsRoot || item.IsTaskGroup;
            e.Handled = true;
        }

        private void AddTaskGroup(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null) return;

            ChoTaskGroupCategory subCategory = null;
            //bool canSendMsg = false;

            try
            {
                subCategory = new ChoTaskGroupCategory(0, String.Empty, null, item);
                subCategory.IsTaskGroup = true;
                subCategory.ParentGroupId = item.Id;
                AddOrEditTaskGroupWindow wnd = new AddOrEditTaskGroupWindow(subCategory);
                bool? retValue = ShowDialog(wnd);
                if (retValue == null || !retValue.Value)
                    return;

                item.Tasks.Add(subCategory);

                LoadGridData(item);

                ////make sure the parent is expanded
                TasksTree.TryFindNode(item).IsExpanded = true;
                TasksTree.TryFindNode(item).IsSelected = true;

                //NOTE this would be an alternative to force layout preservation
                //even if the PreserveLayoutOnRefresh property was false:
                //TreeLayout layout = CategoryTree.GetTreeLayout();
                //CategoryTree.Refresh(layout);

                //Important - mark the event as handled
                //if (canSendMsg)
                //    SendTaskMgmtCommand(subCategory._id, subCategory.Name, item.WorkflowName, item._id, item.Name, subCategory.ScheduleName, ChoOperationType.Add);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            e.Handled = true;
        }

        /// <summary>
        /// Checks whether it is allowed to delete a category, which is only
        /// allowed for nested categories, but not the root items.
        /// </summary>
        private void EvaluateCanAddTask(object sender, CanExecuteRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null) return;

            e.CanExecute = !item.IsRoot && item.IsTaskGroup;
            e.Handled = true;
        }

        /// <summary>
        /// Creates a sub category for the clicked item
        /// and refreshes the tree.
        /// </summary>
        private void AddTask(object sender, ExecutedRoutedEventArgs e)
        {
            ////get the processed item
            ChoTaskGroupCategory item = GetCommandItem();
            if (item == null) return;

            ChoTaskGroupCategory subCategory = null;
            //bool canSendMsg = false;

            try
            {
                subCategory = new ChoTaskGroupCategory(0, String.Empty, null, item);

                AddOrEditTaskWindow wnd = new AddOrEditTaskWindow(subCategory, _machines, _wfNames);
                bool? retValue = ShowDialog(wnd);
                if (retValue == null || !retValue.Value)
                    return;

                //canSendMsg = wnd.IsDataUpdated;
                item.Tasks.Add(subCategory);

                LoadGridData(item);

                ////make sure the parent is expanded
                TasksTree.TryFindNode(item).IsExpanded = true;
                TasksTree.TryFindNode(item).IsSelected = true;

                SendTaskMgmtCommand(item._id, item.Name, item.WorkflowName, item.Parent._id, item.Parent.Name, item.ScheduleName, ChoTaskChangeType.Add);

                //NOTE this would be an alternative to force layout preservation
                //even if the PreserveLayoutOnRefresh property was false:
                //TreeLayout layout = CategoryTree.GetTreeLayout();
                //CategoryTree.Refresh(layout);

                //Important - mark the event as handled
                //if (canSendMsg)
                //    SendTaskMgmtCommand(subCategory._id, subCategory.Name, item.WorkflowName, item._id, item.Name, subCategory.ScheduleName, ChoOperationType.Add);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            e.Handled = true;
        }

        /// <summary>
        /// Determines the item that is the source of a given command.
        /// As a command event can be routed from a context menu click
        /// or a short-cut, we have to evaluate both possibilities.
        /// </summary>
        /// <returns></returns>
        private ChoTaskGroupCategory GetCommandItem(bool refresh = false)
        {
            //get the processed item
            ContextMenu menu = TasksTree.NodeContextMenu;
            if (menu == null) return null;
            if (menu.IsVisible)
            {
                //a context menu was clicked
                TreeViewItem treeNode = (TreeViewItem)menu.PlacementTarget;
                if (treeNode == null)
                    return null;

                ChoTaskGroupCategory cat = (ChoTaskGroupCategory)treeNode.Header;
                if (cat != null && refresh)
                    ChoTaskModel.Refresh(cat);

                return cat;
            }
            else
            {
                if (refresh && TasksTree.SelectedItem != null)
                    ChoTaskModel.Refresh(TasksTree.SelectedItem);

                //the context menu is closed - the user has pressed a shortcut
                return TasksTree.SelectedItem;
            }
        }

        internal static void SendTaskActionCommand(ChoTaskActionType cmdType, string parameters = null)
        {
            if (Instance == null || Instance.SelectedRow == null || Instance._tcpClient == null) return;

            ChoTasksDataSet.CHO_TASKSRow row = Instance.SelectedRow.Row as ChoTasksDataSet.CHO_TASKSRow;
            if (row == null) return;
            if (row.IsSCHEDULE_NAMENull()) return;

            ChoCommandMessage commandRequest = ChoCommandMessage.New(Environment.MachineName, ChoUser.CurrentUser);
            int batchId = row.IsBATCH_IDNull() ? ChoRandom.NextRandom() : row.BATCH_ID;
            if (cmdType == ChoTaskActionType.ActivateTask)
                batchId = ChoRandom.NextRandom();

            if (parameters.IsNullOrWhiteSpace())
            {
                if (cmdType == ChoTaskActionType.ResumeTask && !row.IsBATCH_CMD_PARAMETERSNull())
                    parameters = row.BATCH_CMD_PARAMETERS;
                else if (!row.IsCMD_PARAMETERSNull())
                    parameters = row.CMD_PARAMETERS;
            }

            commandRequest.Command = new ChoTaskActionCommand { TaskName = row.TASK_NAME, WFName = row.WORKFLOW_NAME, ScheduleName = row.SCHEDULE_NAME, BatchId = batchId,
                                                                CommandType = cmdType,
                                                                CommandParameters = parameters, Timeout = row.TIMEOUT.CastTo<int>(), SleepBetweenRetry = row.SLEEP_BETWEEN_RETRY.CastTo<int>(),
                MaxNoOfRetry = row.RETRY_COUNT.CastTo<int>()
            };

            Instance._tcpClient.Send(commandRequest);
        }

        internal static void SendTaskMgmtCommand(int taskId, string taskName, string wfName,
            int taskGroupId, string taskGroupName, string scheduleName, ChoTaskChangeType opType)
        {
            if (Instance == null || Instance._tcpClient == null) return;

            ChoCommandMessage commandRequest = ChoCommandMessage.New();
            commandRequest.Command = new ChoTaskMgmtCommand
            {
                TaskId = taskId,
                TaskName = taskName,
                WorkflowName = wfName,
                TaskGroupId = taskGroupId,
                TaskGroupName = taskGroupName,
                TaskMgmtType = opType,
                ScheduleName = scheduleName
            };

            Instance._tcpClient.Send(commandRequest);
        }

        //internal static void SendCalendarCommand(string calName, ChoOperationType operationType)
        //{
        //    if (Instance == null || Instance._tcpClient == null) return;

        //    ChoCommandMessage commandRequest = ChoCommandMessage.New();
        //    commandRequest.Command = new ChoCalendarCommand { CalendarName = calName, OperationType = operationType };

        //    Instance._tcpClient.Send(commandRequest);
        //}

        //internal static void SendCommand(ChoCommand cmd)
        //{
        //    if (cmd == null) return;

        //    ChoCommandMessage commandRequest = ChoCommandMessage.New();
        //    commandRequest.Command = cmd;

        //    Instance._tcpClient.Send(commandRequest);
        //}

        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            Reconnect();
        }

        private void btnAdmin_Click(object sender, RoutedEventArgs e)
        {
        }

        private void btnHolidayCal_Click(object sender, RoutedEventArgs e)
        {
            AddOrEditHolidayCalWindow addOrEditHolidayCalWindow = new AddOrEditHolidayCalWindow();
            bool? retValue = ShowDialog(addOrEditHolidayCalWindow);
        }

        private void dgTasks_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!_init)
                _lastSelectedGridRow = dgTasks.SelectedIndex;
        }

        private void btnAdminUsers_Click(object sender, RoutedEventArgs e)
        {
            bool canSendMsg = false;
            try
            {

                AddOrEditUserWindow addOrEditUserWindow = new AddOrEditUserWindow();
                bool? retValue = ShowDialog(addOrEditUserWindow);
                if (retValue == null || !retValue.Value)
                    return;

                canSendMsg = addOrEditUserWindow.IsDataUpdated;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            e.Handled = true;
        }

        private static bool? ShowDialog(Window childWindow)
        {
            ChildWindow = childWindow;
            bool? retValue = childWindow.ShowDialog();
            ChildWindow = null;
            return retValue;
        }

        private static bool? ShowDialog(CommonDialog childWindow)
        {
            ChildDialog = childWindow;
            bool? retValue = childWindow.ShowDialog();
            ChildDialog = null;
            return retValue;
        }

        private void btnAdminRoles_Click(object sender, RoutedEventArgs e)
        {
            bool canSendMsg = false;
            try
            {
                AddOrEditRolesWindow addOrEditRolesWindow = new AddOrEditRolesWindow();
                bool? retValue = ShowDialog(addOrEditRolesWindow);
                if (retValue == null || !retValue.Value)
                    return;

                canSendMsg = addOrEditRolesWindow.IsDataUpdated;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
            e.Handled = true;
        }

        private void RaisePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void Window_Activated(object sender, EventArgs e)
        {
            if (ChildWindow != null)
                ChildWindow.Activate();
        }

        private void btnViewClusters_Click(object sender, RoutedEventArgs e)
        {
            if (_clusterNodesViewerWnd == null)
            {
                _clusterNodesViewerWnd = new ChoClusterNodesViewer();
                _clusterNodesViewerWnd.Show();
            }
        }

        private void btnConfigure_Click(object sender, RoutedEventArgs e)
        {
            bool doRefresh = false;
            ChoWorkflowServerSettings settings = new ChoWorkflowServerSettings();
            settings.AfterConfigurationObjectMemberSet += (o, e1) =>
            {
                doRefresh = true;
            };

            ChoConfigurationObjectEditor wnd = new ChoConfigurationObjectEditor(settings);
            wnd.ResizeMode = ResizeMode.CanMinimize;

            wnd.ConfigurationObjectEditorCtrl.ShowTitle = false;
            wnd.Title = "Server Settings";
            wnd.ShowDialog();

            if (doRefresh)
            {
                if (MessageBox.Show("Configuration settings has been modified. {0}Do you want to reconnect to the server?".FormatString(Environment.NewLine), Title, MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                {
                    settings.ControllerIPAddress = "Unknown";
                    Reconnect();
                }
            }
        }
    }
}
